#include "CryptHelper.h"

#include <QByteArray>
#include <QRandomGenerator>
#include<QString>
#include<QDebug>
#include<QTextCodec>
#include <Windows.h>
#include <wincrypt.h>
#include <math.h>
#include <wchar.h>
#include <gmssl/sm3.h>
#include <gmssl/sm4.h>

CryptHelper::CryptHelper() {}

QByteArray CryptHelper::sm3Hash(const QByteArray& data)
{
    SM3_CTX ctx;
    uint8_t hash[SM3_DIGEST_SIZE];

    sm3_init( & ctx);
    sm3_update(
        & ctx,
        reinterpret_cast<const uint8_t*>(data.constData()), // 关键转换
        data.size()
    );
    // 完成哈希计算
    sm3_finish( & ctx, hash);

    return QByteArray(reinterpret_cast<char*>(hash), SM3_DIGEST_SIZE);
}
// PKCS7 填充
QByteArray pkcs7_pad(const QByteArray& data)
{
    int block_size = SM4_BLOCK_SIZE;
    int padding = block_size - (data.size() % block_size);
    return data + QByteArray(padding, padding);
}

QByteArray pkcs7_unpad(const QByteArray& data)
{
    if (data.isEmpty()) return data;
    int padding = data.at(data.size() - 1);
    return data.left(data.size() - padding);
}

QByteArray CryptHelper::sm4Encrypt(const QByteArray& plaintext, const QByteArray& key)
{
    // 验证密钥长度
    if (key.size() != SM4_KEY_SIZE)
    {
        qCritical() << "Invalid SM4 key length (must be 16 bytes)";
        return QByteArray();
    }

    // 生成随机 IV
    QByteArray iv(SM4_BLOCK_SIZE, 0);
    QRandomGenerator::global()->fillRange(reinterpret_cast<quint32*>(iv.data()), iv.size() / sizeof(quint32));

    // 填充数据
    QByteArray padded = pkcs7_pad(plaintext);
    size_t nblocks = padded.size() / SM4_BLOCK_SIZE;

    // 初始化密钥
    SM4_KEY sm4_key;
    sm4_set_encrypt_key( & sm4_key, reinterpret_cast<const uint8_t*>(key.constData()));

    // 加密
    QByteArray ciphertext(iv.size() + padded.size(), 0);
    uint8_t* iv_ptr = reinterpret_cast<uint8_t*>(ciphertext.data());
    uint8_t* out_ptr = iv_ptr + SM4_BLOCK_SIZE;

    // 复制 IV 到输出
    memcpy(iv_ptr, iv.constData(), SM4_BLOCK_SIZE);

    // 调用块加密函数
    sm4_cbc_encrypt_blocks(
        & sm4_key,
        iv_ptr,
        reinterpret_cast<const uint8_t*>(padded.constData()),
        nblocks,
        out_ptr
    );

    return ciphertext;
}

QByteArray CryptHelper::sm4Decrypt(const QByteArray& ciphertext, const QByteArray& key)
{
    // 1. 验证密钥长度
    if (key.size() != SM4_KEY_SIZE)
    {
        qCritical() << "SM4 解密错误：密钥长度必须为 16 字节";
        return QByteArray();
    }

    // 2. 验证密文长度是否足够包含IV
    if (ciphertext.size() < SM4_BLOCK_SIZE)
    {
        qCritical() << "SM4 解密错误：密文长度不足，缺少 IV";
        return QByteArray();
    }

    // 3. 提取 IV 和加密数据
    QByteArray iv = ciphertext.left(SM4_BLOCK_SIZE);
    QByteArray encrypted = ciphertext.mid(SM4_BLOCK_SIZE);

    // 4. 验证加密数据长度是否为块大小的整数倍
    if (encrypted.size() % SM4_BLOCK_SIZE != 0)
    {
        qCritical() << "SM4 解密错误：密文长度不符合块大小要求";
        return QByteArray();
    }

    // 5. 初始化 SM4 解密密钥
    SM4_KEY sm4_key;
    sm4_set_decrypt_key( & sm4_key,
                         reinterpret_cast<const uint8_t*>(key.constData())
                       );

    // 6. 创建 IV 副本以避免修改原始数据
    uint8_t iv_copy[SM4_BLOCK_SIZE];
    memcpy(iv_copy, iv.constData(), SM4_BLOCK_SIZE);

    // 7. 准备解密缓冲区
    QByteArray decrypted(encrypted.size(), 0);

    // 8. 执行块解密
    sm4_cbc_decrypt_blocks(
        & sm4_key,                   // 解密密钥
        iv_copy,                     // 初始化向量副本
        reinterpret_cast<const uint8_t*>(encrypted.constData()), // 输入数据
        encrypted.size() / SM4_BLOCK_SIZE, // 块数量
        reinterpret_cast<uint8_t*>(decrypted.data()) // 输出缓冲区
    );

    // 9. 去除 PKCS7 填充并验证
    QByteArray unpadded = pkcs7_unpad(decrypted);
    if (unpadded.isEmpty())
    {
        qCritical() << "SM4 解密错误：填充验证失败，数据可能被篡改";
        return QByteArray();
    }

    return unpadded;
}

